package com.weixin.project.Service;

import com.weixin.project.Dao.CommentDao;
import com.weixin.project.Dao.ForumQuestionDao;
import com.weixin.project.Entity.ForumQuestion;
import com.weixin.project.Specification.ForumQuestionSpecification;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class ForumService {
    @Value("10")
    Integer pageSize;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    ForumQuestionDao forumQuestionDao;
    @Autowired
    CommentDao forumCommentDao;
    private final static String FORUM_QUESTION = "forum_question";
    private final static String FORUM_QUESTION_READ_HASH = "forum_question_read";
    @CachePut(value = FORUM_QUESTION, key = "#result.id", unless = "#result == null ")
    public ForumQuestion storeQuestion(ForumQuestion question) {
        return forumQuestionDao.save(question);
    }

    @Cacheable(value = FORUM_QUESTION, key = "#questionId", unless = "#result == null ")
    public ForumQuestion findQuestion(Integer questionId){
        Optional<ForumQuestion> forumQuestionOptional = forumQuestionDao.findById(questionId);
        return forumQuestionOptional.isPresent()?forumQuestionOptional.get():null;
    }

    public Page<ForumQuestion> findQuestions(Integer page){
        Sort sort = Sort.by("id").ascending();
        Pageable pageable = PageRequest.of(page, pageSize, sort);
        Page<ForumQuestion> questionPage = forumQuestionDao.findAll(pageable);
        return questionPage;
    }

    public List<ForumQuestion> searchQuestionsWithTokens(String[] tokens) {
        List<ForumQuestion> questions =
                forumQuestionDao.findAll(ForumQuestionSpecification.imgOrContentContainsTokens(tokens));
        // 对结果进行排序
        List<ForumQuestion> sortedQuestions = questions.stream()
                .filter(question -> countTokensInString(question.getContent(), question.getImageText(), tokens) >= tokens.length)
                .sorted(Comparator.comparingInt((ForumQuestion question) -> countTokensInString(question.getContent(), question.getImageText(), tokens)).reversed())
                .collect(Collectors.toList());
        return sortedQuestions;
    }

    private int countTokensInString(String content, String imageText, String[] tokens) {
        int count = 0;
        for (String token : tokens) {
            count += content.split(token, -1).length - 1;
            count += imageText.split(token, -1).length - 1;
        }
        return count;
    }

    public Integer getReadCount(ForumQuestion question){
        String key = "key::" + question.getId();
        if(!redisTemplate.boundHashOps(FORUM_QUESTION_READ_HASH).hasKey(key)){
            redisTemplate.boundHashOps(FORUM_QUESTION_READ_HASH).put(key, question.getReadCount());
        }
        return Integer.parseInt(redisTemplate.boundHashOps(FORUM_QUESTION_READ_HASH).get(key).toString());
    }

    public void incReadCount(ForumQuestion question) {
        String key = "key::" + question.getId();
        if(!redisTemplate.boundHashOps(FORUM_QUESTION_READ_HASH).hasKey(key)){
            redisTemplate.boundHashOps(FORUM_QUESTION_READ_HASH).put(key, question.getReadCount());
        }
        redisTemplate.boundHashOps(FORUM_QUESTION_READ_HASH).put(key, getReadCount(question) + 1);
    }

    public Page<ForumQuestion> findQuestionsOfUser(Integer page, Integer userId){
        Sort sort = Sort.by("id").ascending();
        Pageable pageable = PageRequest.of(page, pageSize, sort);
        Page<ForumQuestion> questionPage = forumQuestionDao.getForumQuestionsByOriginId(userId, pageable);
        return questionPage;
    }

    public void deleteQuestion(ForumQuestion question){
        forumQuestionDao.delete(question);
    }

    public Integer countAllQuestions() {
        Long num = forumQuestionDao.count();
        return num.intValue();
    }

    public Integer countQuestionsOfUser(Integer userId){
        return forumQuestionDao.countForumQuestionsByOriginId(userId);
    }

    public void transReadCountFromRedis2DB(){
        if(!redisTemplate.hasKey(FORUM_QUESTION_READ_HASH)) return;
        Set<String> keys = redisTemplate.boundHashOps(FORUM_QUESTION_READ_HASH).keys();
        for (String key:
                keys) {
            String[] split = key.split("::");
            Integer questionId = Integer.parseInt(split[1]);
            ForumQuestion question = findQuestion(questionId);
            question.setReadCount(Integer.parseInt(
                    redisTemplate.boundHashOps(FORUM_QUESTION_READ_HASH).get(key).toString()));
            storeQuestion(question);
            redisTemplate.boundHashOps(FORUM_QUESTION_READ_HASH).delete(key);
        }
    }

}
